/**
 *  optional 实现思路：用一个标志位标志是否有值，用一个实际的空间去存储那个值
 *
 */
#include <iostream>
#include <utility>     // for std::move, std::forward
#include <stdexcept>   // for std::bad_optional_access
#include <type_traits> // for std::is_nothrow_move_constructible

class bad_optional_access : public std::exception
{
public:
    const char *what() const noexcept override
    {
        return "Bad optional access";
    }
};

template <typename T>
class Optional
{
public:
    Optional() noexcept
        : has_value_(false)
    {
    }

    Optional(const T &value)
        : has_value_(true)
    {
        new (&storage_) T(value); // 定位new，在storage_的空间内构造 T 对象
    }

    Optional(T &&value) noexcept(std::is_nothrow_move_constructible<T>::value)
        : has_value_(true)
    {
        new (&storage_) T(std::move(value));
    }

    Optional(const Optional &other)
        : has_value_(other.has_value_)
    {
        if (has_value_)
        {
            new (&storage_) T(*other);
        }
    }

    Optional(Optional &&other) noexcept(std::is_nothrow_move_constructible<T>::value)
        : has_value_(other.has_value_)
    {
        if (has_value_)
        {
            new (&storage_) T(std::move(*other));
            other.reset();
        }
    }

    ~Optional()
    {
        reset();
    }

    // 赋值运算符
    Optional &operator=(const Optional &other)
    {
        if (this != &other)
        {
            reset();
            if (other.has_value_)
            {
                has_value_ = true;
                new (&storage_) T(*other);
            }
        }
        return *this;
    }

    // 移动赋值运算符
    Optional &operator=(Optional &&other) noexcept(std::is_nothrow_move_constructible<T>::value)
    {
        if (this != &other)
        {
            reset();
            if (other.has_value_)
            {
                has_value_ = true;
                new (&storage_) T(std::move(*other));
                other.reset();
            }
        }
        return *this;
    }

    // 判断是否包含有效值
    bool has_value() const noexcept
    {
        return has_value_;
    }

    // 获取值的引用
    T &value()
    {
        if (!has_value_)
        {
            throw bad_optional_access();
        }
        return *reinterpret_cast<T *>(&storage_);
    }

    const T &value() const
    {
        if (!has_value_)
        {
            throw bad_optional_access();
        }
        return *reinterpret_cast<const T *>(&storage_);
    }

    // 获取值的引用，解引用运算符
    T &operator*()
    {
        return value();
    }

    const T &operator*() const
    {
        return value();
    }

    // 获取值的指针
    T *operator->()
    {
        return &value();
    }

    const T *operator->() const
    {
        return &value();
    }

    // 重置 Optional，使其为原初状态：有申请存储空间，但没有构造T对象
    void reset() noexcept
    {
        if (has_value_)
        {
            reinterpret_cast<T *>(&storage_)->~T(); // 析构storage_存储的T对象
            has_value_ = false;
        }
    }

    // 赋值新值
    template <typename... Args>
    void emplace(Args &&...args)
    {
        reset();
        new (&storage_) T(std::forward<Args>(args)...);
        has_value_ = true;
    }

private:
    bool has_value_;                                                     // 是否有值的标志
    typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_; // 存储空间，但是未初始化，只有当有值时，才初始化。
};

template <typename T>
Optional<T> make_optional(T &&value) // 工厂函数，创建 Optional 对象
{
    return Optional<T>(std::forward<T>(value));
}
